package com.jdd.modules.sdkidentifyresultpushlog.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.jdd.common.api.vo.Result;
import com.jdd.common.exception.JddException;
import com.jdd.common.util.*;
import com.jdd.modules.order.entity.ParkOrderInfo;
import com.jdd.modules.parking.entity.ParkArmInfo;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.entity.ParkInfo;
import com.jdd.modules.parking.mapper.ParkArmInfoMapper;
import com.jdd.modules.parking.mapper.ParkInfoMapper;
import com.jdd.modules.parking.service.IParkWorkStationService;
import com.jdd.modules.parking.service.IparkCarEnterLogService;
import com.jdd.modules.sdkidentifyresultpushlog.dto.ParkGetCarFeeLogV3DTO;
import com.jdd.modules.sdkidentifyresultpushlog.entity.ParkOrderInfoVO;
import com.jdd.modules.sdkidentifyresultpushlog.service.ChargeFeeV2Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 新版月租车计费服务
 * @author liuyaowen
 * */
@Service
@Slf4j
public class ChargeFeeV2ServiceImpl implements ChargeFeeV2Service {

    @Resource
    private ParkInfoMapper parkInfoMapper;
    @Resource
    private ParkArmInfoMapper parkArmInfoMapper;
    @Resource
    private IparkCarEnterLogService parkCarEnterLogService;
    @Resource
    private PackageFeeLogUtils packageFeeLogUtils;
    @Resource
    private ChargeFeeUtils chargeFeeUtils;
    @Resource
    private IParkWorkStationService parkWorkStationService;
    /**
     * 该方法是有牌车出口码计费入口,在该方法中将在对入场纪录做处理之后开始计费
     */
    @Override
    public Result<?> outParkChargeFeeV2(String parkCode,String plateNo,String serialNo,String imgPath){
        log.info("计费服务类,出场码计费,传入参数:车场编号:{},车牌号:{},设备序列号:{}", parkCode, plateNo, serialNo);
        ParkGetCarFeeLogV3DTO parkGetCarFeeLogV3DTO = new ParkGetCarFeeLogV3DTO();
        try {
            ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(serialNo);
            if (parkArmInfo == null) {
                return Result.error("车道信息不存在");
            }
            Date outTime = new Date();
            List<ParkCarEnterLog> carAllEnterLogs = new ArrayList<>();
            try {
                carAllEnterLogs = parkCarEnterLogService.getParkCarEnterLog(plateNo, parkCode);
            } catch (JddException e) {
                if (e.getCode() == ResultCode.PARAMETER_ERROR) {
                    return Result.error(ResultCode.NO_ENTER_LOG, "车辆无入场纪录");
                }
            }
            // 使用车辆出场识别信息制作一个入场假纪录辅助计费
            ParkCarEnterLog lastEnterLog = new ParkCarEnterLog();
            lastEnterLog.setParkCode(parkCode);
            lastEnterLog.setCarEnterTime(DateUtil.format(outTime, "yyyy-MM-dd HH:mm:ss"));
            carAllEnterLogs.add(lastEnterLog);
            ParkOrderInfoVO parkOrderInfoVO = this.chargeFee(carAllEnterLogs, parkArmInfo, null, outTime, parkGetCarFeeLogV3DTO);
            parkOrderInfoVO.setOutImgPath(imgPath);
            //停车场入口名称
            parkOrderInfoVO.setEnterArmName(carAllEnterLogs.get(0).getArmName());
            //入场抓拍图片地址
            parkOrderInfoVO.setImgPath(carAllEnterLogs.get(0).getImgPath());
            //入场云图片地址
            parkOrderInfoVO.setOssImgPath(carAllEnterLogs.get(0).getOssImgPath());
            log.info("计费服务类,出场码计费结果：{}", parkOrderInfoVO);
            parkGetCarFeeLogV3DTO.setParkOrderInfoVO(parkOrderInfoVO);
            return Result.ok(parkGetCarFeeLogV3DTO);
        } catch (Exception e) {
            log.error("计费服务类,异常信息", e);
            throw new JddException(ResultCode.INTERNAL_SERVER_ERROR, "计费服务类,出场码计费系统错误," + e.getMessage());
        }
    }

    @Override
    public Result<?> chargeFeeAgain(String serialNo, String plateNo, String carTypeId) {
        log.info("计费服务类,指定车辆类型重新计费,传入参数:车道设备序列号:{},车牌号:{},车辆类型id:{}", serialNo, plateNo,carTypeId);
        try {
            ParkArmInfo parkArmInfo = parkArmInfoMapper.queryParkArmInfoBySerialNo(serialNo);
            String parkCode = parkArmInfo.getParkCode();
            Date outTime = new Date();
            String outTimeStr = DateUtil.format(outTime, "yyyy-MM-dd HH:mm:ss");
            List<ParkCarEnterLog> carAllEnterLogs = new ArrayList<>();
            try {
                carAllEnterLogs = parkCarEnterLogService.getParkCarEnterLog(plateNo, parkCode);
            } catch (JddException e) {
                if (e.getCode() == ResultCode.PARAMETER_ERROR) {
                    log.error("车辆无入场记录");
                    return Result.error("车辆无入场记录");
                }else {
                    log.error("算费服务异常："+e.getMessage());
                    return Result.error(e.getMessage());
                }
            }
            // 使用车辆出场识别信息制作一个入场假纪录辅助计费
            ParkCarEnterLog lastEnterLog = new ParkCarEnterLog();
            lastEnterLog.setParkCode(parkCode);
            lastEnterLog.setCarEnterTime(outTimeStr);
            carAllEnterLogs.add(lastEnterLog);
            ParkOrderInfoVO parkOrderInfoVO = this.chargeFee(carAllEnterLogs,parkArmInfo,carTypeId,outTime,null);
            //返回订单信息，因为需要传到云端
            log.info("计费服务类,出场码计费结果：{}", parkOrderInfoVO);
            return Result.ok("计费成功").setResult(parkOrderInfoVO);
        } catch (Exception e) {
            log.error("计费服务类,异常信息", e);
            throw new JddException(ResultCode.INTERNAL_SERVER_ERROR, "计费服务类,出场码计费系统错误," + e.getMessage());
        }
    }


    private ParkOrderInfoVO chargeFee(List<ParkCarEnterLog> carAllEnterLogs,ParkArmInfo parkArmInfo,String carTypeId,Date outTime,ParkGetCarFeeLogV3DTO parkGetCarFeeLogV3DTO){
        long unPayFee = 0;
        ParkCarEnterLog firstEnterLog = carAllEnterLogs.get(0);
        // 遍历入场纪录,对车辆在每个车场内的停车时间进行算费。
        long chargeFee = chargeFeeUtils.chargeTotalFeeMonthlyV3(carAllEnterLogs,carTypeId,parkGetCarFeeLogV3DTO);
        // 根据最近的入场记录id查询对应的支付订单
        Map map = packageFeeLogUtils.getOrderInfo(firstEnterLog.getId());
        // 得到车辆的已支付金额
        int paidFee = (int) map.get("paidFee");
        List<ParkOrderInfo> orderInfos = (List<ParkOrderInfo>) map.get("orderInfoList");
        // 如果存在车辆的已支付订单
        if (CollectionUtils.isNotEmpty(orderInfos)) {
            // 得到最近支付的一条订单信息
            ParkOrderInfo order = orderInfos.get(0);
            // 得到支付时间
            Date payTime = order.getCreateTime();
            long time = DateUtil.between(payTime, outTime, DateUnit.MINUTE);
            ParkInfo parkInfo = parkInfoMapper.getFreeMinutes();
            int freeMinutes = parkInfo.getFreeMinutes();
            if (time >= freeMinutes) {
                unPayFee = chargeFee - paidFee;
            }
        } else {
            unPayFee = chargeFee;
        }
        unPayFee = unPayFee<0?0:unPayFee;
        try {
            Date carEnterTime = DateUtils.stringToDate(firstEnterLog.getCarEnterTime(), "yyyy-MM-dd HH:mm:ss");
            ParkOrderInfoVO parkOrderInfoVO = new ParkOrderInfoVO();
            Date endDate = new Date();
            parkOrderInfoVO.setId(SnowFlakeUtil.getId()).
                    setCarEnterId(firstEnterLog.getId()).
                    setIpAddr(parkArmInfo.getIpAddr()).
                    setSerialNo(parkArmInfo.getSerialNo()).
                    setParkCode(parkArmInfo.getParkCode()).
                    setParkName(parkArmInfo.getParkName()).
                    setEnterTime(firstEnterLog.getCarEnterTime()).
                    setOutTime(DateUtils.dateToString(endDate, "yyyy-MM-dd HH:mm:ss")).
                    setType(firstEnterLog.getCarTypeNo()).
                    setCarTypeId(firstEnterLog.getCarTypeId()).
                    setPlateNo(firstEnterLog.getPlateNo()).
                    setChargeDuration((int) DateUtils.timeDiff2(carEnterTime, endDate)).
                    setArmName(parkArmInfo.getArmName()).
                    setOrderStatus("1").
                    setChargePaid(String.valueOf(paidFee)).
                    setChargeDue(String.valueOf(unPayFee)).
                    setChargeTotalFee(String.valueOf(chargeFee)).
                    setChargeUnpaid(String.valueOf(unPayFee)).
                    setChargePrepaid(String.valueOf(paidFee)).
                    setTotalDiscAmt((int) map.get("totalDiscAmt"));

            //加上工作站名和岗亭人账户
            String workUser = parkWorkStationService.getStationOperationNameByParkArm(parkArmInfo);
            if(ObjectUtil.isNotEmpty(workUser)){
                parkOrderInfoVO.setWorkName(parkArmInfo.getWorkStationName());
                parkOrderInfoVO.setSysUserName(workUser);
            }
            return parkOrderInfoVO;
        } catch (Exception e) {
            log.error("算费异常"+e.getMessage());
            throw new JddException(ResultCode.INTERNAL_SERVER_ERROR,e.getMessage());
        }
    }

}
